﻿using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Text.RegularExpressions;

namespace zijian666.CommandLine;

/// <summary>
/// 用于标记命令行选项的属性或字段
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public partial class OptionAttribute : Attribute
{
    /// <summary>
    /// 选项的默认值工厂
    /// </summary>
    private Func<object>? _defaultValue;
    /// <summary>
    /// 初始化一个新的 <see cref="OptionAttribute"/> 实例。
    /// </summary>
    public OptionAttribute() { }
    /// <summary>
    /// 初始化一个新的 <see cref="OptionAttribute"/> 实例。
    /// </summary>
    /// <param name="name"></param>
    public OptionAttribute(string? name) => Name = name;

    /// <summary>
    /// 是否忽略此选项
    /// </summary>
    public bool Ignore { get; set; } = false;
    /// <summary>
    /// 选项的名称
    /// </summary>
    public string? Name { get; set; }
    /// <summary>
    /// 选项的别名
    /// </summary>
    public string[]? Alias { get; set; }

    /// <summary>
    /// 设置选项的默认值
    /// </summary>
    public object? DefaultValue
    {
        set => _defaultValue = () => value;
    }

    /// <summary>
    /// 获取选项的默认值工厂
    /// </summary>
    public Func<object>? DefaultValueFactory => _defaultValue;
    /// <summary>
    /// 选项的描述
    /// </summary>
    public string? Description { get; set; }

    /// <summary>
    /// 选项是否为必需
    /// </summary>
    public bool? Required { get; set; }

    /// <summary>
    /// 选项值的类型
    /// </summary>
    internal Type? ValueType { get; set; }

    /// <summary>
    /// 根据成员的特性解析选项的名称、描述、别名、值类型和是否必需
    /// </summary>
    /// <param name="member"> 成员信息 </param>
    /// <exception cref="InvalidOperationException"></exception>
    [MemberNotNull(nameof(Name), nameof(Description), nameof(ValueType), nameof(Alias), nameof(Required))]
    internal void Resolve(MemberInfo member)
    {
        Name ??= member.GetCustomAttribute<System.ComponentModel.DisplayNameAttribute>()?.DisplayName;
        Description ??= member.GetCustomAttribute<System.ComponentModel.DescriptionAttribute>()?.Description;
        ValueType ??= member switch
        {
            PropertyInfo pi => pi.PropertyType,
            FieldInfo fi => fi.FieldType,
            _ => throw new InvalidOperationException($"成员 {member.Name} 不是属性或字段")
        };
        Alias ??= [];
        Required ??= !IsNullable(member);
        if (_defaultValue is null)
        {
            if (member.GetCustomAttribute<DefaultValueAttribute>() is { } def)
            {
                DefaultValue = def.Value;
            }
            else if (ValueType.IsEnum && Enum.IsDefined(ValueType, 0))
            {
                if (!Required.Value)
                {
                    DefaultValue = Enum.Parse(ValueType, "0");
                }
            }
            else
            {
                var instance = Activator.CreateInstance(member.ReflectedType!);
                var value = member switch
                {
                    PropertyInfo pi => pi.GetValue(instance),
                    FieldInfo fi => fi.GetValue(instance),
                    _ => null
                };
                if (value is not null)
                {
                    if (ValueType.IsValueType && Nullable.GetUnderlyingType(ValueType) == null)
                    {
                        if (!value.Equals(Activator.CreateInstance(ValueType)))
                        {
                            DefaultValue = value;
                        }
                    }
                    else
                    {
                        DefaultValue = value;
                    }
                }
            }

        }
        //DefaultValue ??= member.GetCustomAttribute<DefaultValueAttribute>()?.Value;

        if (string.IsNullOrWhiteSpace(Name))
        {
            Name = member.Name;
            if (Name.StartsWith("m_", StringComparison.OrdinalIgnoreCase) ||
                Name.StartsWith("_", StringComparison.OrdinalIgnoreCase))
            {
                Name = Name.Substring(Name.IndexOf('_') + 1);
            }
            Name = Name.ToLowerInvariant();
        }
        if (string.IsNullOrWhiteSpace(Description))
        {
            Description = $"Sets the {Name} option.";
        }
        if (!NameAliasRegex().IsMatch(Name))
        {
            throw new InvalidOperationException($"选项名称 {Name} 不合法, 只能包含字母数字和连字符, 只能字母开头");
        }
        foreach (var alias in Alias)
        {
            if (!NameAliasRegex().IsMatch(alias))
            {
                throw new InvalidOperationException($"选项别名 {alias} 不合法, 只能包含字母数字和连字符, 只能字母开头");
            }
        }
    }
    /// <summary>
    /// 名称和别名只允许字母数字和连字符, 只允许字母开头
    /// </summary>
    /// <returns></returns>
    [GeneratedRegex("^[a-zA-Z][a-zA-Z0-9-]*$")]
    private static partial Regex NameAliasRegex();


    /// <summary>
    /// 检查成员是否为可空类型
    /// </summary>
    /// <param name="member"> 成员信息 </param>
    /// <returns></returns>
    public static bool IsNullable(MemberInfo member)
    {
        if (member is not (FieldInfo or PropertyInfo))
        {
            throw new ArgumentException("Member must be of type FieldInfo or PropertyInfo", nameof(member));
        }

        // 值类型不可空
        var type = member is FieldInfo field ? field.FieldType : ((PropertyInfo)member).PropertyType;

        if (type.IsValueType && Nullable.GetUnderlyingType(type) is null)
        {
            return false;
        }
        // required 关键字检查
        // [Required] 特性检查
#if NET7_0_OR_GREATER
        if (member.IsDefined(typeof(System.Runtime.CompilerServices.RequiredMemberAttribute), false)
        || member.IsDefined(typeof(System.ComponentModel.DataAnnotations.RequiredAttribute), false))
        {
            return false;
        }
#else
        if (!member.CustomAttributes.Any(a =>
                a.AttributeType.FullName == "System.ComponentModel.DataAnnotations.RequiredAttribute"
                || a.AttributeType.FullName == "System.Runtime.CompilerServices.RequiredMemberAttribute"))
        {
            return false;
        }
#endif

        // 2. 可空引用类型检查（NullableAttribute）
        var nullableAttr = member.CustomAttributes
            .FirstOrDefault(a => a.AttributeType.FullName == "System.Runtime.CompilerServices.NullableAttribute");
        if (nullableAttr != null)
        {
            var arg = nullableAttr.ConstructorArguments.First().Value;
            if (arg is byte b)
            {
                return b == 2;
            }
            else if (arg is IReadOnlyCollection<CustomAttributeTypedArgument> args && args.Count > 0)
            {
                return args.First().Value is byte b1 && b1 == 2;
            }
        }


        // 3. 可空引用类型上下文检查（NullableContextAttribute）
        var enable = EnableNullableFeature(member);

        // 如果启用了可空引用类型特性，则默认为不可空
        return !enable;
    }

    /// <summary>
    /// 获取是否启用可空引用类型特性
    /// </summary>
    /// <param name="member"> 成员信息 </param>
    /// <returns></returns>
    private static bool EnableNullableFeature(MemberInfo member)
    {
        // 先查成员本身
        return get(member.GetCustomAttributes() ?? [])
            // 再查声明类型
            ?? get(member.DeclaringType?.GetCustomAttributes() ?? [])
            // 最后查程序集
            ?? get(member.Module.Assembly.GetCustomAttributes() ?? [])
            ?? false;

        static bool? get(IEnumerable<Attribute> attributes)
        {
            foreach (var attr in attributes)
            {
                var type = attr.GetType();
                if (type.FullName == "System.Runtime.CompilerServices.NullableContextAttribute")
                {
                    var flagField = type.GetField("Flag");
                    if (flagField?.GetValue(attr) is byte b)
                    {
                        return b == 1;
                    }
                }
            }
            return null;

        }
    }


}